/**
 * 
 */
package org.jenkon.commons.lang.utils;

import java.util.ArrayList;
import java.util.List;

import org.jenkon.commons.lang.filter.EqualsFilter;
import org.jenkon.commons.lang.filter.Filter;

/**
 * Util class with helping methods for arrays.
 * 
 * @author jkonopka
 * 
 */
public final class ArrayUtils {

	private static final int INDEX_NOT_FOUND = -1;

	/**
	 * hide public constructor for this util class.
	 */
	private ArrayUtils() {
	}

	/**
	 * <p>
	 * Check the array of is empty.
	 * </p>
	 * <p>
	 * <code>values == null</code> return true<br>
	 * <code>values.length == 0</code> return true<br>
	 * <code>values.length > 0</code> return false<br>
	 * </p>
	 * 
	 * @param values array with the values
	 * @return <code>true</code> or <code>false</code>
	 */
	public static boolean isEmpty(final Object[] values) {
		return values == null || values.length == 0;
	}

	/**
	 * <p>
	 * Check the array of is not empty.
	 * </p>
	 * <p>
	 * <code>values == null</code> return false<br>
	 * <code>values.length != 0</code> return false<br>
	 * <code>values.length == 0</code> return true<br>
	 * </p>
	 * 
	 * @param values array with the values
	 * @return <code>true</code> or <code>false</code>
	 */
	public static boolean isNotEmpty(final Object[] values) {
		return !isEmpty(values);
	}

	/**
	 * <p>
	 * Get the length of a array.
	 * </p>
	 * <p>
	 * <code>null</code> return 0<br>
	 * <code>0</code> return 0<br>
	 * <code>>0</code> return the length<br>
	 * </p>
	 * 
	 * @param values the array with values
	 * @return the size of the values
	 */
	public static int sizeOf(final Object[] values) {
		return isEmpty(values) ? 0 : values.length;
	}

	/**
	 * Filter the array with {@link Filter}.
	 * 
	 * @param values array with the values
	 * @param filter the {@link Filter} implementation
	 * @return the result of array
	 * @see Filter
	 * @throws NullPointerException if {@link Filter} or array is <code>null</code>
	 */
	public static <T> Object[] filter(final T[] values, final Filter<T> filter) {

		final List<T> results = new ArrayList<T>();

		for (final T value : values) {
			if (filter.accept(value)) {
				results.add(value);
			}
		}

		return results.toArray();

	}

	/**
	 * Check if contain the array a object by filter.
	 * 
	 * @param values array with values
	 * @param filter the {@link Filter} implementation
	 * @return <code>true</code> or <code>false</code>
	 * @see Filter
	 * @throws NullPointerException if {@link Filter} or the array is <code>null</code>
	 */
	public static <T> boolean contains(final T[] values, final Filter<T> filter) {

		for (final T value : values) {
			if (filter.accept(value)) {
				return true;
			}
		}

		return false;

	}

	/**
	 * Check if contain the array the value.
	 * 
	 * @param values the array with the values
	 * @param value the object to check if contain the array the value
	 * @return <code>true</code> or <code>false</code>
	 * @see #contains(Object[], Filter)
	 * @throws NullPointerException if the array or the value object is <code>null</code>
	 */
	public static <T> boolean contains(final T[] values, final T value) {
		return contains(values, new EqualsFilter<T>(value));
	}

	/**
	 * Get the index of the elemet from array.
	 * 
	 * @param values the array with value objects
	 * @param value the object to search in the array
	 * @return if the array is empty or the value was not found in the array then return {@value #INDEX_NOT_FOUND}, else the position from value
	 *         object in the array
	 * @throws NullPointerException if the searched value is <code>null</code>
	 */
	public static <T> int indexOf(final T[] values, final T value) {

		if (ArrayUtils.isEmpty(values)) {
			return INDEX_NOT_FOUND;
		}

		for (int index = 0; index < values.length; index++) {
			if (values[index].equals(value)) {
				return index;
			}
		}

		return INDEX_NOT_FOUND;

	}

	/**
	 * Check if the two arrays have the same length.
	 * 
	 * @param left the left array
	 * @param right the right array
	 * @return <code>true</code> or <code>false</code>
	 */
	public static <T> boolean isSameLength(final T[] left, final T[] right) {

		if (ArrayUtils.isEmpty(left) && ArrayUtils.isEmpty(right)) {
			return true;
		}

		if (ArrayUtils.isEmpty(left) && ArrayUtils.isNotEmpty(right)) {
			return false;
		}

		if (ArrayUtils.isNotEmpty(left) && ArrayUtils.isEmpty(right)) {
			return false;
		}

		if (left.length == right.length) {
			return true;
		}

		return false;

	}

	/**
	 * Check if the two arrays have not the same length.
	 * 
	 * @param left the left array
	 * @param right the right array
	 * @return <code>true</code> or <code>false</code>
	 */
	public static <T> boolean isNotSameLength(final T[] left, final T[] right) {
		return !isSameLength(left, right);
	}

}
